
#include "RtBase.h"
#include "RtChannelHttpBase.h"
#include "RtHttpUtilClasses.h"
#include "RtMessageBlock.h"

CRtChannelHttpBase::CRtChannelHttpBase(IRtTransport *aTransport)
	: m_pTransportId(aTransport)
	, m_pSink(NULL)
	, m_bIsFirstSend(TRUE)
	, m_pMbSendBuf(NULL)
	, m_dwSendBufMaxLen(1024 * 1024)
	, m_customContentLength(FALSE)
	, m_pThreadUser(NULL)
	, m_bStream(FALSE)
	, m_bFullResponse(FALSE)
	, m_needOnSend(FALSE)
{
	RT_ASSERTE(m_pTransportId);

#ifdef RT_DEBUG
	m_pThreadUser = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_CURRENT);
	RT_ASSERTE(m_pThreadUser);
#endif // RT_DEBUG
}

CRtChannelHttpBase::~CRtChannelHttpBase()
{
	if (m_pMbSendBuf) {
		m_pMbSendBuf->DestroyChained();
		m_pMbSendBuf = NULL;
	}
}

RtResult CRtChannelHttpBase::
SetContentLength_i(CRtHttpHeaderArray &aHead, CRtMessageBlock *aData)
{
	DWORD dwLen;
	if (aData)
		dwLen = aData->GetChainedLength();
	else
		dwLen = 0;

	char szLen[32] = "";
	if(dwLen!=0)
		::sprintf(szLen, "%d", dwLen);
	BOOL bRet = aHead.SetHeader(CRtHttpAtomList::Content_Length, szLen);
	return bRet ? RT_OK : RT_ERROR_FAILURE;
}

RtResult CRtChannelHttpBase::SendData_i(CRtMessageBlock &aData)
{
	RT_ASSERTE_RETURN(m_pTransport, RT_ERROR_NOT_INITIALIZED);
#ifdef RT_DEBUG
	RT_ASSERTE(CRtThreadManager::IsEqualCurrentThread(m_pThreadUser->GetThreadId()));
#endif // RT_DEBUG

	if ( m_needOnSend || (m_pMbSendBuf && m_pMbSendBuf->GetChainedLength() >= m_dwSendBufMaxLen) )
	{
		m_needOnSend = TRUE;
		return RT_ERROR_PARTIAL_DATA;
	}

	RtResult rv;
	if (m_pMbSendBuf==NULL) {
		rv = m_pTransport->SendData(aData);
		if (RT_FAILED(rv)) {
			m_pMbSendBuf = aData.DuplicateChained();
		}
	}
	else {
		m_pMbSendBuf->Append(aData.DuplicateChained());
	}
	return RT_OK;
}

RtResult CRtChannelHttpBase::Close_t(RtResult aReason)
{
	RtResult rv = RT_OK;
	if (m_pTransport) {
		rv = m_pTransport->Disconnect(aReason);
		m_pTransport = NULL;
	}
	m_pSink = NULL;
	return rv;
}

void CRtChannelHttpBase::
OnReceive(CRtMessageBlock &aData, IRtTransport *aTrptId, 
		  CRtTransportParameter *)
{
	RT_ASSERTE(m_pTransport.Get() == aTrptId);
	
	RtResult rv = ParserHttpProtocol_t(aData);
	if (RT_SUCCEEDED(rv)) {
		if (!m_pSink) {
			// this channel is Cannel()ed because ParserHttpProtocol_t() will
			// call OnDataArrival() when it parsed the HTTP head.
			return;
		}
		if (aData.GetChainedLength() > 0) 
			m_pSink->OnReceive(aData, m_pTransportId);
	}
	else if (rv == RT_ERROR_PARTIAL_DATA) {
		// we need more data to parse HTTP protocol.
	}
	else {
		IRtTransportSink* pSinkTmp = m_pSink;
		Close_t(rv);
		RT_ASSERTE(pSinkTmp);
		if (pSinkTmp)
			pSinkTmp->OnDisconnect(rv, m_pTransportId);
	}
}

void CRtChannelHttpBase::
OnSend(IRtTransport *aTrptId, CRtTransportParameter *)
{
	RT_ASSERTE(m_pTransport.Get() == aTrptId);
	RT_ASSERTE(m_pMbSendBuf);
	if (m_pMbSendBuf==NULL)
		return;

	RtResult rv = m_pTransport->SendData(*m_pMbSendBuf);
	if (RT_FAILED(rv)) {
		m_pMbSendBuf = m_pMbSendBuf->ReclaimGarbage();
	}
	else {
		m_pMbSendBuf->DestroyChained();
		m_pMbSendBuf = NULL;
	}

	RT_ASSERTE(m_pSink);
	if (m_needOnSend && (m_pMbSendBuf==NULL || m_pMbSendBuf->GetChainedLength()<m_dwSendBufMaxLen) && m_pSink)
	{
		m_needOnSend = FALSE;
		m_pSink->OnSend(m_pTransportId);
	}
}

void CRtChannelHttpBase::
OnDisconnect(RtResult aReason, IRtTransport *aTrptId)
{
	RT_WARNING_TRACE_THIS("CRtChannelHttpBase::OnDisconnect, rv="
		<<aReason<<" trpt="<<aTrptId<<" sink="<<m_pSink);
	RT_ASSERTE(m_pTransport.Get() == aTrptId);
	
	IRtTransportSink* pSinkTmp = m_pSink;
	Close_t(aReason);

	RT_ASSERTE(pSinkTmp);
	if (pSinkTmp)
		pSinkTmp->OnDisconnect(aReason, m_pTransportId);
}

RtResult CRtChannelHttpBase::SetOption_i(DWORD aCommand, LPVOID aArg)
{
	switch(aCommand) {
	case CS_OPT_MAX_SENDBUF_LEN:
		m_dwSendBufMaxLen = *static_cast<DWORD*>(aArg);
// 		RT_ASSERTE(m_dwSendBufMaxLen >= 64 * 1024 || m_dwSendBufMaxLen == 0);
		return RT_OK;
		
	case RT_OPT_CHANNEL_HTTP_HEADER_CUSTOM_CONTENT_LENGTH:
		m_customContentLength = *static_cast<BOOL*>(aArg);
		return RT_OK;

	case RT_OPT_CHANNEL_HTTP_STREAM:
		m_bStream = *static_cast<BOOL*>(aArg);
		m_bIsFirstSend = TRUE; // Re-initialize sending parameters. 
		return RT_OK;

	default:
		if (m_pTransport)
			return m_pTransport->SetOption(aCommand, aArg);
		else
			return RT_ERROR_NULL_POINTER;
	}
	return RT_OK;
}

RtResult CRtChannelHttpBase::GetOption_i(DWORD aCommand, LPVOID aArg)
{
	switch(aCommand) {
	case CS_OPT_MAX_SENDBUF_LEN:
		*(static_cast<DWORD*>(aArg)) = m_dwSendBufMaxLen;
		return RT_OK;

	case RT_OPT_CHANNEL_HTTP_HEADER_CUSTOM_CONTENT_LENGTH:
		*static_cast<BOOL*>(aArg) = m_customContentLength;
		return RT_OK;

	case RT_OPT_TRANSPORT_TRAN_TYPE:
		*(static_cast<CRtConnectionManager::CType*>(aArg)) 
			= CRtConnectionManager::CTYPE_HTTP;
		return RT_OK;
		
	case RT_OPT_CHANNEL_HTTP_STREAM:
		*static_cast<BOOL*>(aArg) = m_bStream;
		return RT_OK;

	default:
		if (m_pTransport)
			return m_pTransport->GetOption(aCommand, aArg);
		else
			return RT_ERROR_NULL_POINTER;
	}
	return RT_OK;
}


/** 
 * Fix the issue that http header does not be removed from content 
 * when OnReceive to upper layer next time in the same connection, 
 * by Webb Zheng 20070130. 
 */
void CRtChannelHttpBase::OnResponseFinished()
{
//	RT_INFO_TRACE_THIS("CRtChannelHttpBase::OnResponseFinished()");
	m_bFullResponse = TRUE;
}
